package com.car.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.car.account.controller.form.storesForm.StoresCodeLoginForm;
import com.car.account.controller.form.storesForm.StoresPassLoginForm;
import com.car.account.dto.storesDto.ClerkDto;
import com.car.account.dto.storesDto.SelectClerkDto;
import com.car.account.dto.storesDto.StoresDto;
import com.car.account.entity.ClerRole;
import com.car.account.entity.Stores;
import com.car.account.exception.AccountException;
import com.car.account.mapper.StoresMapper;
import com.car.account.param.storesParam.InsertClerkParam;
import com.car.account.param.storesParam.SelectClerkDtoParam;
import com.car.account.param.storesParam.UpdateClerkRoleParam;
import com.car.account.rabbitmq.SendLoginCodeConsumer;
import com.car.account.service.ClerRoleService;
import com.car.account.service.StoresService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.car.account.util.ListUtil;
import com.car.account.util.PageDtoUtil;
import com.car.account.util.aliyunUtil.AliyunOssUtil;
import com.car.account.util.validatorUtil.PasswordValidator;
import com.car.account.util.validatorUtil.PhoneNumberValidator;
import com.car.commons.web.util.MD5util;
import com.car.commons.web.util.RedisKeyUtil;
import com.car.commons.web.util.RedisUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 董旭
 * @since 2024-08-28
 */
@Service
public class StoresServiceImpl extends ServiceImpl<StoresMapper, Stores> implements StoresService {

    @Resource
    private StoresService storesService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private SendLoginCodeConsumer sendLoginCodeConsumer;

    @Resource
    private ClerRoleService clerRoleService;

    @Resource
    private AliyunOssUtil aliyunOssUtil;

    @Resource
    private StoresMapper storesMapper;

    @Override
    public Integer storesPassLogin(StoresPassLoginForm form) throws Exception {
        //判断是否存在门店账号
        Stores stores = storesService.getOne(new QueryWrapper<Stores>()
                .eq("clerk_phone", form.getClerkPhone())
                .ne("clerk_state", 2));
        if (stores == null) throw new AccountException(3000,"门店账号不存在");
        //判断状态是否正常
        if (stores.getClerkState() == 1) throw new AccountException(3001,"门店账号被禁用");
        //判断密码是否正确
        if (!MD5util.md5(form.getClerkPhone(),form.getClerkPass()).equals(stores.getClerkPass()))
            throw new AccountException(3002,"密码错误");
        return stores.getClerkId();
    }

    @Override
    public void sendStoresLoginCode(String clerkPhone) throws Exception {
        //判断是否存在门店账号
        Stores stores = storesService.getOne(new QueryWrapper<Stores>()
                .eq("clerk_phone", clerkPhone)
                .ne("clerk_state", 3));
        if (stores == null) throw new AccountException(3000,"门店账号不存在");
        //判断状态是否正常
        if (stores.getClerkState() == 1) throw new AccountException(3001,"门店账号被禁用");
        //判断一分钟内重复发送
        if (redisUtil.hasKey(RedisKeyUtil.loginCodeOnMinute(clerkPhone)))
            throw new AccountException(3003,"请勿在1分钟内重复发送");
        //判断一小时内发送次数
        if (!redisUtil.hasKey(RedisKeyUtil.sendNumbers(clerkPhone))) {
            redisUtil.set(RedisKeyUtil.sendNumbers(clerkPhone), "1", 60*60);
        }
        String num = redisUtil.get(RedisKeyUtil.sendNumbers(clerkPhone));
        if (!num.isEmpty() && Integer.parseInt(num) >= 5) {
            throw new AccountException(3004,"一小时内发送验证码超出5条，稍后再试");
        }
        sendLoginCodeConsumer.sendLoginCode(clerkPhone);
    }

    @Override
    public Integer storesCodeLogin(StoresCodeLoginForm form) throws Exception {
        //判断是否存在门店账号
        Stores stores = storesService.getOne(new QueryWrapper<Stores>()
                .eq("clerk_phone", form.getClerkPhone())
                .ne("clerk_state", 3));
        if (stores == null) throw new AccountException(3000,"门店账号不存在");
        //判断状态是否正常
        if (stores.getClerkState() == 1) throw new AccountException(3001,"门店账号被禁用");
        //验证验证码
        if (!redisUtil.hasKey(RedisKeyUtil.loginCodeKey(form.getClerkPhone())))
            throw new AccountException(3005,"无效验证码");
        String code = redisUtil.get(RedisKeyUtil.loginCodeKey(form.getClerkPhone()));
        if (!code.equals(form.getCode()))
            throw new AccountException(3006,"验证码有误");
        //删除redis验证码
        redisUtil.del(RedisKeyUtil.loginCodeKey(form.getClerkPhone()));
        return stores.getClerkId();
    }

    @Override
    public ClerkDto selectClerkDto(Integer clerkId) throws Exception {
        //判断是否存在门店账号
        Stores stores = getById(clerkId);
        if (stores == null || stores.getClerkState() == 2) throw new AccountException(3001,"店员账号不存在");
        //判断门店账号状态
        if (stores.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        ClerkDto clerkDto = BeanUtil.toBean(stores, ClerkDto.class);
        return clerkDto;
    }

    @Override
    public Page<SelectClerkDto> selectClerks(SelectClerkDtoParam param) throws Exception {
        //判断是否存在店员账号
        Stores currentClerk = getById(param.getCurrentClerkId());
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        //开启分页
        Page<SelectClerkDto> page = new Page<>(param.getCurrent() == null ? 1 : param.getCurrent(), param.getSize() == null ? 6 : param.getSize());
        Page<SelectClerkDto> clerkDtoPage = storesMapper.findClerkInfo(page, currentClerk.getStoresId(), param.getClerkName(), param.getClerkPhone(), param.getClerkState());
        return clerkDtoPage;
    }

    @Override
    @Transactional
    public void clerkUpdatePass(Integer clerkId, String clerkPass) throws Exception {
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        //判断密码格式
        if (!PasswordValidator.isValidPassword(clerkPass)) throw new AccountException(3003,"密码格式有误");
        //修改密码
        clerk.setClerkPass(MD5util.md5(clerk.getClerkPhone(),clerkPass));
        updateById(clerk);
    }

    @Override
    @Transactional
    public String clerkUpdateImage(MultipartFile mf, Integer clerkId) throws Exception {
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        String imageName = aliyunOssUtil.upImage(mf);
        //修改头像
        clerk.setImage(imageName);
        updateById(clerk);
        return imageName;
    }

    @Override
    @Transactional
    public void clerkUpdatePhone(Integer clerkId, String clerkPhone) throws Exception {
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        //判断手机号格式
        if (!PhoneNumberValidator.isValidPhoneNumber(clerkPhone))
            throw new AccountException(3003,"手机号格式有误");
        //判断手机号是否已经被绑定
        Stores stores = getOne(new QueryWrapper<Stores>()
                .eq("clerk_phone", clerkPhone)
                .ne("clerk_state", 2));
        if (stores != null) throw new AccountException(3004,"手机号已经被绑定");
        //修改绑定手机号
        clerk.setClerkPhone(clerkPhone);
        updateById(clerk);
    }

    @Override
    @Transactional
    public  void insertClerk(InsertClerkParam param) throws Exception {
        //判断是否存在店员账号
        Stores currentClerk = getById(param.getCurrentClerkId());
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        //判断手机号格式
        if (!PhoneNumberValidator.isValidPhoneNumber(param.getClerkPhone()))
            throw new AccountException(3003,"手机号格式有误");
        //判断手机号是否已经被绑定
        Stores storesByPhone = getOne(new QueryWrapper<Stores>()
                .eq("clerk_phone", param.getClerkPhone())
                .ne("clerk_state", 2));
        if (storesByPhone != null) throw new AccountException(3004,"手机号已经被绑定");
        //添加店员
        Stores stores = new Stores();
        stores.setClerkName(param.getClerkName());
        stores.setClerkPhone(param.getClerkPhone());
        stores.setClerkPass(MD5util.md5(param.getClerkPhone(), "123456"));
        stores.setImage("https://superman-book.oss-cn-chengdu.aliyuncs.com/%E7%94%A8%E6%88%B7%E9%BB%98%E8%AE%A4%E5%A4%B4%E5%83%8F.png");
        stores.setStoresId(currentClerk.getStoresId());
        stores.setClerkState(0);
        boolean isSave = save(stores);
        if (isSave) {
            ClerRole clerRole = new ClerRole();
            clerRole.setClerkId(stores.getClerkId());
            clerRole.setRoleId(param.getClerkRole());
            clerRoleService.save(clerRole);
        }else  throw new AccountException(3005,"添加失败");
    }

    @Override
    public List<StoresDto> findsClerksByIds(Integer currentClerkId, Set<Integer> clerkIds) throws Exception {
        //判断是否存在店员账号
        Stores currentClerk = getById(currentClerkId);
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        List<Stores> stores = list(new QueryWrapper<Stores>().in("clerk_id", clerkIds));
        return ListUtil.copyToList(stores, StoresDto.class);
    }

    @Override
    @Transactional
    public void disableClerk(Integer currentClerkId, Integer clerkId) throws Exception {
        //判断是否存在店长账号
        Stores currentClerk = getById(currentClerkId);
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店长账号不存在");
        //判断当前店长账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店长账号已被禁用");
        //判断是否为当前账号
        if (currentClerkId == clerkId) throw new AccountException(3003,"不能对当前账号操作");
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3004,"店员账号不存在");
        //判断店员账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3005,"店员账号已经是禁用状态");
        clerk.setClerkState(1);
        updateById(clerk);
    }

    @Override
    @Transactional
    public void enableClerk(Integer currentClerkId, Integer clerkId) throws Exception {
        //判断是否存在店长账号
        Stores currentClerk = getById(currentClerkId);
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店长账号不存在");
        //判断当前店长账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店长账号已被禁用");
        //判断是否为当前账号
        if (currentClerkId == clerkId) throw new AccountException(3003,"不能对当前账号操作");
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3004,"店员账号不存在");
        //判断店员账号状态
        if (clerk.getClerkState() == 0) throw new AccountException(3005,"店员账号已经是启用状态");
        clerk.setClerkState(0);
        updateById(clerk);
    }

    @Override
    public Integer findStoresIdByClerkId(Integer clerkId) throws Exception {
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3001,"店员账号不存在");
        //判断当前门店账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3002,"店员账号已被禁用");
        return clerk.getStoresId();
    }

    @Override
    public Integer selectStoresRole(Integer currentClerkId, Integer clerkId) throws Exception {
        //判断是否存在店长账号
        Stores currentClerk = getById(currentClerkId);
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店长账号不存在");
        //判断当前店长账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店长账号已被禁用");
        //判断是否为当前账号
        if (currentClerkId == clerkId) throw new AccountException(3003,"不能对当前账号操作");
        //判断是否存在店员账号
        Stores clerk = getById(clerkId);
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3004,"店员账号不存在");
        //判断店员账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3005,"店员账号是禁用状态");
        ClerRole clerRole = clerRoleService.getOne(new QueryWrapper<ClerRole>().eq("clerk_id", clerkId));
        return clerRole.getRoleId();
    }

    @Override
    @Transactional
    public void updateClerkRole(UpdateClerkRoleParam param) throws Exception {
        //判断是否存在店长账号
        Stores currentClerk = getById(param.getCurrentClerkId());
        if (currentClerk == null || currentClerk.getClerkState() == 2)
            throw new AccountException(3001,"店长账号不存在");
        //判断当前店长账号状态
        if (currentClerk.getClerkState() == 1) throw new AccountException(3002,"店长账号已被禁用");
        //判断是否为当前账号
        if (param.getCurrentClerkId() == param.getClerkId()) throw new AccountException(3003,"不能对当前账号操作");
        //判断是否存在店员账号
        Stores clerk = getById(param.getClerkId());
        if (clerk == null || clerk.getClerkState() == 2)
            throw new AccountException(3004,"店员账号不存在");
        //判断店员账号状态
        if (clerk.getClerkState() == 1) throw new AccountException(3005,"店员账号是禁用状态");
        //判断是否是同一个店的同事
        if (currentClerk.getStoresId() != clerk.getStoresId()) throw new AccountException(3006,"无法操作其他门店账号");
        //删除曾经身份
        clerRoleService.remove(new QueryWrapper<ClerRole>()
                .eq("clerk_id", clerk.getClerkId()));
        //创建新身份
        ClerRole clerRole = new ClerRole();
        clerRole.setRoleId(param.getRoleId());
        clerRole.setClerkId(param.getClerkId());
        clerRoleService.save(clerRole);
    }
}
